/*
 * @Author: LVGRAPE
 * @LastEditors: LVGRAPE
 */

#include "zino.h"
#include "os_timer.h"
#include "zino_shell.h"
#include "uart.h"
#include <string.h>
#include <stdlib.h>
#define DBG_TAG "shell"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>

static os_timer_t timer;

const char __zsc_help_name[] RT_SECTION(".rodata.name") = "help";
const char __zsc_help_desc[] RT_SECTION(".rodata.name") = "zino shell help";
volatile const struct zino_shell_syscall* zs_ptr;
long zino_shell_help(int argc, char** argv);
const struct zino_shell_syscall zs_start RT_SECTION(".zino_init_fn.7") =
{
    __zsc_help_name,__zsc_help_desc,zino_shell_help
};
const struct zino_shell_syscall zs_end RT_SECTION(".zino_init_fn.8.end");
long zino_shell_help(int argc, char** argv)
{
    rt_kprintf("Zino shell help:\n");
    for (zs_ptr = &zs_start; zs_ptr < &zs_end; zs_ptr++)
    {
        rt_kprintf("%s \t", zs_ptr->name);
        rt_kprintf("-%s\n", zs_ptr->desc);
    }
}

static uint8_t get_argc(const char* str)
{
    uint8_t argc = 1;
    for (uint8_t i = 0; i < strlen(str); i++)
    {
        if (str[i] == ' ')
        {
            argc++;
        }
    }
    return argc;
}
#define SHELL_MAX_ARGC 8
#define SHELL_MAX_ARGV_LEN 16
static uint8_t get_argv_len(const char* str)
{
    uint8_t len = 0;
    for (uint8_t i = 0; i < strlen(str); i++)
    {
        len++;
        if (str[i] == ' ')
        {
            break;
        }
    }
    return (len > SHELL_MAX_ARGV_LEN ? SHELL_MAX_ARGV_LEN : len);
}
void shell_task(void* pvParameters)
{
    // LOG_D("shell_task");
    if (IsSerialRxHasData(&serialHandle[serial1]))
    {
        char* rx_ptr = Serial_gets(&serialHandle[serial1]);
        uint8_t cmd_exist = 0;
        for (zs_ptr = &zs_start; zs_ptr < &zs_end; zs_ptr++)
        {
            if (strncmp(rx_ptr, zs_ptr->name, strlen(zs_ptr->name)) == 0)
            {
                uint8_t argc = get_argc(rx_ptr);
                if (argc > 8)
                {
                    LOG_E("max argc < %d!", SHELL_MAX_ARGC);
                    break;
                }
                char arg[SHELL_MAX_ARGC][SHELL_MAX_ARGV_LEN] = { 0 };
                char* argv[SHELL_MAX_ARGC] = { 0 };
                // rt_kprintf("\n> %s,%d\n", rx_ptr, argc);
                for (uint8_t i = 0; i < argc; i++)
                {
                    strncpy(arg[i], rx_ptr, get_argv_len(rx_ptr));
                    argv[i] = arg[i];
                    rx_ptr = strchr(rx_ptr, ' ');
                    // rt_kprintf("argv[%d]:%s,%x\n", i, argv[i]);
                    if (rx_ptr == NULL)
                    {
                        break;
                    }
                    rx_ptr++;
                }
                // rt_kprintf("fun\n");
                zs_ptr->fun(argc, argv);
                cmd_exist++;
                break;
            }
        }
        if (!cmd_exist)
        {
            rt_kprintf("> Unknow cmd: %s\n", rx_ptr);
        }
        rt_kprintf("\n>");
        Serial_Purge(&serialHandle[serial1]);
    }
    // return 0;
}
int shell_init(void)
{
    os_timer_init(&timer, shell_task, 0);
    os_timer_start(&timer, 1, 1);
    LOG_D("shell_init");
    return 0;
}


int check_shell_list(void)
{
    volatile const struct zino_shell_syscall* zs_ptr;
    // rt_kprintf("\r\n\r\n zino_components_init: %08X-%08X \r\n",&__zino_init_zi_board_end,&__zino_init_zi_end);
    for (zs_ptr = &zs_start; zs_ptr < &zs_end; zs_ptr++)
    {
        LOG_D("check_shell_list: name:%s", zs_ptr->name);
        LOG_D("desc:%s \n", zs_ptr->desc);
        LOG_D("fun:%08X \n", zs_ptr->fun);
    }
    return 0;
}
ZINO_APP_EXPORT(shell_init);
ZINO_APP_EXPORT(check_shell_list);

void reboot()
{
    __set_PRIMASK(0);
    NVIC_SystemReset();
}
// long cmd1(void) {}
// long cmd2(void) {}
// long cmd3(void) {}

ZINO_CMD_EXPORT(reboot, system reboot);
// ZINO_CMD_EXPORT(cmd2, cmd2 test);
// ZINO_CMD_EXPORT(cmd3, cmd3 test);
